﻿using Hx.ADSyncPlatform.ActiveDirectory.Attributes;
using Hx.ADSyncPlatform.ActiveDirectory.Enums;
using Hx.ADSyncPlatform.ActiveDirectory.Model;
using System.Collections.Generic;
using System.DirectoryServices;
using System.Linq;
using System.Text;

namespace Hx.ADSyncPlatform.ActiveDirectory.Access
{
    /// <summary>
    /// 计算机访问
    /// </summary>
    internal class ComputerAccess
    {

        /// <summary>
        /// 单个计算机
        /// </summary>
        /// <param name="rootEntry">查询的根AD对象</param>
        /// <param name="sAMAccountName">计算机账户名</param>
        /// <returns>单个计算机信息SearchResult
        /// </returns>
        public SearchResult Single(DirectoryEntry rootEntry, string sAMAccountName)
        {
            string filter = string.Format("(&(objectclass=Computer)(sAMAccountName={0}))", sAMAccountName);
            DirectorySearcher dsearcher = new DirectorySearcher(rootEntry, filter, null, SearchScope.Subtree);
            SearchResult result = dsearcher.FindOne();
            return result;
        }

        /// <summary>
        /// 绑定计算机的用户列表
        /// </summary>
        /// <param name="rootEntry">查询的根AD对象</param>
        /// <param name="sAMAccountName">计算机账户名</param>
        /// <returns>单个计算机信息SearchResult
        /// </returns>
        public SearchResultCollection BindUsers(DirectoryEntry rootEntry, string sAMAccountName)
        {
            string filter = string.Format("(&(objectclass=user)(userWorkstations=*{0}*))", sAMAccountName.Replace("$", "").ToLower());
            DirectorySearcher dsearcher = new DirectorySearcher(rootEntry, filter, null, SearchScope.Subtree);
            SearchResultCollection resultCollection = dsearcher.FindAll();
            return resultCollection;
        }

        /// <summary>
        /// 查询组织下的计算机
        /// </summary>
        /// <param name="org">组织</param>
        /// <param name="searchScope">查询层级</param>
        /// <returns>返回计算机SearchResultCollection</returns>
        public SearchResultCollection Get(DirectoryEntry org, SearchScope searchScope)
        {
            string filter = "(objectclass=Computer)";
            DirectorySearcher dsearcher = new DirectorySearcher(org, filter, null, SearchScope.Subtree);
            SearchResultCollection result = dsearcher.FindAll();
            return result;
        }

        /// <summary>
        /// 查询组织下的计算机
        /// </summary>
        /// <param name="org">组织</param>
        /// <param name="searchScope">查询层级</param>
        /// <returns>返回计算机SearchResultCollection</returns>
        public SearchResultCollection Get(DirectoryEntry org, SearchScope searchScope, string name = "")
        {
            string filter = "(objectclass=Computer)";
            if (!string.IsNullOrEmpty(name))
            {
                filter = string.Format("(&(objectclass=Computer)(sAMAccountName={0}*))", name);
            }
            DirectorySearcher dsearcher = new DirectorySearcher(org, filter, null, searchScope);
            SearchResultCollection result = dsearcher.FindAll();
            return result;
        }

        /// <summary>
        /// 查询组织下的计算机
        /// </summary>
        /// <param name="org">组织</param>
        /// <param name="searchScope">查询层级</param>
        /// <returns>返回计算机SearchResultCollection</returns>
        public SearchResultCollection GetByInfo(DirectoryEntry org, SearchScope searchScope, string info)
        {
            List<string> prefixs = new string[] { "hd", "ds", "pd", "jxl" }.ToList();
            StringBuilder sb1 = new StringBuilder();
            prefixs.ForEach(n =>
            {
                sb1.Append($"(name={n}*)");
            });
            string filter = string.Format("(&(objectclass=Computer)(|(info={0}){1}))", info, sb1.ToString());
            DirectorySearcher dsearcher = new DirectorySearcher(org, filter, null, searchScope);
            SearchResultCollection result = dsearcher.FindAll();
            return result;
        }

        /// <summary>
        ///自定义查询
        /// </summary>
        /// <param name="rootEntry">查询的根AD对象</param>
        /// <param name="filter">LDAP查询语句</param>
        /// <param name="propertiesToLoad">需要返回的属性</param>
        /// <param name="searchScope">查询层级</param>
        /// <param name="pageSize">最大条数</param>
        /// <returns>返回计算机SearchResultCollection</returns>
        public SearchResultCollection Search(DirectoryEntry rootEntry, string filter, List<string> propertiesToLoad, SearchScope searchScope, int pageSize)
        {
            DirectorySearcher dsearcher = new DirectorySearcher(rootEntry, filter, propertiesToLoad?.ToArray(), searchScope);
            //hack:确定分页代码可用？
            if (pageSize > 0)
            {
                dsearcher.PageSize = pageSize;
            }
            SearchResultCollection searchResult = dsearcher.FindAll();
            return searchResult;
        }

        /// <summary>
        /// 删除
        /// </summary>
        /// <param name="computerDe">需要删除的计算机</param>
        /// <returns>成功True，失败False</returns>
        public bool Delete(DirectoryEntry computerDe)
        {
            computerDe.DeleteTree();
            return true;
        }

        /// <summary>
        /// 移动
        /// </summary>
        /// <param name="orgDe">移动的目标组织</param>
        /// <param name="computerDe">需要移动的计算机</param>
        /// <returns>成功True，失败False</returns>
        public bool Move(DirectoryEntry orgDe, DirectoryEntry computerDe)
        {
            computerDe.MoveTo(orgDe);
            return true;
        }


        /// <summary>
        /// 创建计算机
        /// </summary>
        /// <param name="computerDe">需要创建的计算机</param>
        /// <returns>成功True，失败False</returns>
        public bool Create(DirectoryEntry orgDe, Computer computer)
        {

            var de = orgDe.Children.Add("CN=" + computer.CN, "computer");
            //de.Properties["sAMAccountName"].Value = computer.SamAccountName;
            //de.Properties["info"].Value = computer.Info;
            //de.Properties["cn"].Value = computer.CN;
            //de.Properties["name"].Value = computer.Name;


            foreach (var property in computer.GetType().GetProperties())
            {
                if (computer.AssignedAttributes.Contains(property.Name))
                {
                    var readOnlyCustom = property.GetCustomAttributes(typeof(ReadOnlyCustomAttribute), false);
                    var v = property.GetValue(computer, null);
                    if ((readOnlyCustom == null || readOnlyCustom.Length == 0))
                    {
                        if (v == null)
                        {
                            de.Properties[property.Name].Clear();
                        }
                        else
                        {
                            if (property.Name?.ToLower() != "accountExpires".ToLower())
                            {

                                de.Properties[property.Name].Value = v;
                            }
                        }
                    }
                }
            }
            //de.Properties["userAccountControl"].Value = (int)UserAccountControlValue.NORMAL_ACCOUNT;
            de.Properties["userAccountControl"].Value = 0x1020;


            de.CommitChanges();
            return true;

        }

        /// <summary>
        /// 修改计算机
        /// </summary>
        /// <param name="computerDe">需要修改的计算机</param>
        /// <returns>成功True，失败False</returns>
        public bool Update(DirectoryEntry computerDe, Computer computer)
        {
            foreach (var property in computer.GetType().GetProperties())
            {
                if (computer.AssignedAttributes.Contains(property.Name))
                {
                    var notUpdate = property.GetCustomAttributes(typeof(IgnoreUpdateAttribute), false);
                    var readOnlyCustom = property.GetCustomAttributes(typeof(ReadOnlyCustomAttribute), false);
                    var v = property.GetValue(computer, null);
                    if ((notUpdate == null || notUpdate.Length == 0) && (readOnlyCustom == null || readOnlyCustom.Length == 0))
                    {
                        if (v == null)
                        {
                            computerDe.Properties[property.Name].Clear();
                        }
                        else
                        {
                            if (property.Name?.ToLower() != "accountExpires".ToLower())
                            {
                                computerDe.Properties[property.Name].Value = v;
                            }
                        }
                    }
                }
            }
            computerDe.CommitChanges();

            return true;

        }

    }
}
